package support.limit.utils;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import support.limit.enums.RateLimitConstantEnums;
import support.limit.enums.RateLimitTypeEnum;
import support.limit.exception.RateLimitException;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 获取key工具类
 *
 * @Description KeyUtil
 * @Author guoyb
 * @Date 2023/12/22 15:53
 */
@Slf4j
public class KeyUtil {

    public static String compositeKey(String identifier, String key) {
        return identifier + ":" + key + ":";
    }

    /**
     * 通过spring Spel 获取参数
     *
     * @param key            定义的key值 以#开头 例如:#user
     * @param parameterNames 形参
     * @param values         形参值
     * @param keyConstant    key的常亮
     * @return
     */
    public List<String> getVauleBySpel(String key, String[] parameterNames, Object[] values, String keyConstant) {
        List<String> keys = new ArrayList<>();
        if (!key.contains("#")) {
            String s = key + keyConstant;
            log.info("没有使用spel表达式value->{}", s);
            keys.add(s);
            return keys;
        }
        //spel解析器
        ExpressionParser parser = new SpelExpressionParser();
        //spel上下文
        EvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < parameterNames.length; i++) {
            context.setVariable(parameterNames[i], values[i]);
        }
        Expression expression = parser.parseExpression(key);
        Object value = expression.getValue(context);
        if (value != null) {
            if (value instanceof List) {
                List value1 = (List) value;
                for (Object o : value1) {
                    keys.add("redisson:lock:" + o.toString() + keyConstant);
                }
            } else if (value.getClass().isArray()) {
                Object[] obj = (Object[]) value;
                for (Object o : obj) {
                    keys.add("redisson:lock:" + o.toString() + keyConstant);
                }
            } else {
                keys.add("redisson:lock:" + value.toString() + keyConstant);
            }
        }
        log.info("spel表达式key={},value={}", key, keys);
        return keys;
    }


    /**
     * 获取key
     *
     * @param joinPoint
     * @param rateLimitTypeEnum
     * @return
     */
    public static String getRateKey(JoinPoint joinPoint, RateLimitTypeEnum rateLimitTypeEnum) {
        // prefix += StringUtils.hasText(lock4j.name()) ? lock4j.name() :
        //         invocation.getMethod().getDeclaringClass().getName() + invocation.getMethod().getName();

        StringBuffer key = new StringBuffer(RateLimitConstantEnums.HASH_TAG);

        // 以方法名加参数列表作为key
        if (RateLimitTypeEnum.ALL.equals(rateLimitTypeEnum)) {
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

            key.append(methodSignature.getMethod().getName());
            Class[] parameterTypes = methodSignature.getParameterTypes();
            Arrays.stream(parameterTypes).forEach(parameter -> {
                key.append(parameter.getName());
            });
            key.append(joinPoint.getTarget().getClass());
        }
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        HttpServletRequest request = requestAttributes.getRequest();
        //  以ip作为key
        if (RateLimitTypeEnum.IP.equals(rateLimitTypeEnum)) {
            key.append(IPUtils.getIpAddr(request));
        }

        // 以自定义作为key
        if (RateLimitTypeEnum.CUSTOM.equals(rateLimitTypeEnum)) {
            if (null != request.getAttribute(RateLimitConstantEnums.CUSTOM)) {
                key.append(request.getAttribute(RateLimitConstantEnums.CUSTOM).toString());
            } else {
                throw new RateLimitException("not found custom info ,please check request.getAttribute('syj-rateLimit-custom')!!!");
            }
        }
        return key.toString();
    }


    /**
     * 通过spring SpEL 获取参数
     *
     * @param key            定义的key值 以#开头 例如:#user
     * @param parameterNames 形参
     * @param values         形参值
     * @param keyConstant    key的常亮
     * @return
     */
    public List<String> getValueBySpEL(String key, String[] parameterNames, Object[] values, String keyConstant) {
        List<String> keys = new ArrayList<>();
        if (!key.contains("#")) {
            String s = "redis:lock:" + key + keyConstant;
            log.debug("lockKey:" + s);
            keys.add(s);
            return keys;
        }
        //spel解析器
        ExpressionParser parser = new SpelExpressionParser();
        //spel上下文
        EvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < parameterNames.length; i++) {
            context.setVariable(parameterNames[i], values[i]);
        }
        Expression expression = parser.parseExpression(key);
        Object value = expression.getValue(context);
        if (value != null) {
            if (value instanceof List) {
                List value1 = (List) value;
                for (Object o : value1) {
                    addKeys(keys, o, keyConstant);
                }
            } else if (value.getClass().isArray()) {
                Object[] obj = (Object[]) value;
                for (Object o : obj) {
                    addKeys(keys, o, keyConstant);
                }
            } else {
                addKeys(keys, value, keyConstant);
            }
        }
        log.info("表达式key={},value={}", key, keys);
        return keys;
    }

    private void addKeys(List<String> keys, Object o, String keyConstant) {
        keys.add("redis:lock:" + o.toString() + keyConstant);
    }




    /**
     * 获取
     *
     * @param joinPoint
     * @param rateLimitTypeEnum
     * @return
     */
    public static String getRateKey1(JoinPoint joinPoint, RateLimitTypeEnum rateLimitTypeEnum) {

        StringBuffer key = new StringBuffer(RateLimitConstantEnums.HASH_TAG);

        // 以方法名加参数列表作为key
        if (RateLimitTypeEnum.ALL.equals(rateLimitTypeEnum)) {
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

            key.append(methodSignature.getMethod().getName());
            Class[] parameterTypes = methodSignature.getParameterTypes();
            Arrays.stream(parameterTypes).forEach(parameter -> {
                key.append(parameter.getName());
            });
            key.append(joinPoint.getTarget().getClass());
        }
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        HttpServletRequest request = requestAttributes.getRequest();
        //  以ip 作为key

        if (RateLimitTypeEnum.IP.equals(rateLimitTypeEnum)) {
            key.append(IPUtils.getIpAddr(request));
        }
        // 以自定义作为key
        if (RateLimitTypeEnum.CUSTOM.equals(rateLimitTypeEnum)) {
            if (null != request.getAttribute(RateLimitConstantEnums.CUSTOM)) {

                key.append(request.getAttribute(RateLimitConstantEnums.CUSTOM).toString());
            } else {
                throw new RateLimitException("not found custom info ,please check request.getAttribute('syj-rateLimit-custom')!!!");
            }
        }
        return key.toString();
    }


}
